package com.meilai.project.controller.web.report.service;

import cn.hutool.core.collection.CollUtil;
import com.meilai.project.controller.web.report.dto.DrawRateDetailBuildingDTO;
import com.meilai.project.controller.web.report.dto.DrawRateDetailCommonDTO;
import com.meilai.project.controller.web.report.dto.DrawRateDetailDTO;
import com.meilai.project.controller.web.report.entity.BuildingLockCount;
import com.meilai.project.controller.web.report.entity.BuildingTotalCount;
import com.meilai.project.controller.web.report.entity.DrawRateSummaryLockCount;
import com.meilai.project.controller.web.report.entity.DrawRateSummaryTotalCount;
import com.meilai.project.controller.web.report.mapper.DrawRateReportMapper;
import com.meilai.project.controller.web.report.vo.*;
import com.meilai.project.entity.business.building.BuildingAreaAudienceRelation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author xchen
 * @since 2022-04-14
 */
@Service
public class DrawRateServiceImpl implements DrawRateService {

	@Autowired
	private DrawRateReportMapper baseMapper;

	@Override
	public List<DrawRateSummaryVO> drawRateSummary(DrawRateDetailDTO req) {
		List<DrawRateSummaryVO> result = new ArrayList<>();
		req.initDateRange();
		List<DrawRateSummaryTotalCount> totalCountList = baseMapper.queryDrawRateSummaryTotalCount();
		List<DrawRateSummaryLockCount> lockCountList = baseMapper.queryDrawRateSummaryLockCount(req.getStart_date(), req.getEnd_date());
		Map<Integer, Integer> lockCountMap = lockCountList.stream().collect(Collectors.toMap(DrawRateSummaryLockCount::getMedia_type_id,
				DrawRateSummaryLockCount::getLock_count));
		for (DrawRateSummaryTotalCount item : totalCountList) {
			DrawRateSummaryVO drawRateSummaryVO = new DrawRateSummaryVO();
			drawRateSummaryVO.setMedia_type_id(item.getMedia_type_id());
			drawRateSummaryVO.setType_name(item.getType_name());
			drawRateSummaryVO.setMedia_total_count(item.getMedia_total_count());
			drawRateSummaryVO.setMedia_publish_count(lockCountMap.get(item.getMedia_type_id()));
			result.add(drawRateSummaryVO);
		}

		List<DrawRateSummaryTotalCount> areaTotalCountList = baseMapper.queryDrawRateSummaryAreaTotalCount();
		List<DrawRateSummaryLockCount> areaLockCountList = baseMapper.queryDrawRateSummaryAreaLockCount(req.getStart_date(), req.getEnd_date());
		Map<String, Integer> areaLockCountMap = areaLockCountList.stream().collect(Collectors.toMap(DrawRateSummaryLockCount::getArea,
				DrawRateSummaryLockCount::getLock_count));
		for (DrawRateSummaryTotalCount item : areaTotalCountList) {
			DrawRateSummaryVO drawRateSummaryVO = new DrawRateSummaryVO();
			drawRateSummaryVO.setMedia_type_id(item.getMedia_type_id());
			drawRateSummaryVO.setType_name(item.getType_name());
			drawRateSummaryVO.setAdcode(item.getAdcode());
			drawRateSummaryVO.setMedia_total_count(item.getMedia_total_count());
			drawRateSummaryVO.setMedia_publish_count(areaLockCountMap.get(item.getType_name()));
			result.add(drawRateSummaryVO);
		}

		//最后计算remain和百分比
		for (DrawRateSummaryVO drawRateSummaryVO : result) {
			Integer media_total_count = drawRateSummaryVO.getMedia_total_count();
			Integer media_publish_count = drawRateSummaryVO.getMedia_publish_count();
			if (media_publish_count == null || 0 == media_publish_count) {
				drawRateSummaryVO.setMedia_remain_count(media_total_count);
				drawRateSummaryVO.setMedia_publish_rate(BigDecimal.ZERO);
				continue;
			}
			drawRateSummaryVO.setMedia_remain_count(media_total_count - media_publish_count);
			drawRateSummaryVO.setMedia_publish_rate(BigDecimal.valueOf(media_publish_count)
					.divide(BigDecimal.valueOf(media_total_count), 2, RoundingMode.HALF_EVEN));
		}

		return result;
	}


	@Override
	public DrawRateDetailCommonVO drawRateDetailCommon(DrawRateDetailCommonDTO req) {
		DrawRateDetailCommonVO result = new DrawRateDetailCommonVO();
		req.initDateRange();
		List<DrawRateDetailCommonItemVO> detailCommonVOList =
				baseMapper.queryDrawRateDetailCommon(req.getMedia_type_id(), null);
		List<BuildingLockCount> buildingLockCounts =
				baseMapper.queryDrawRateDetailCommonLockCount(req.getMedia_type_id(),
						req.getStart_date(), req.getEnd_date(), null);
		DrawRateDetailRateInfo totalRate = calcDrawRate(detailCommonVOList, buildingLockCounts);
		result.setList(detailCommonVOList);
		result.setTotalRate(totalRate);
		return result;
	}

	private DrawRateDetailRateInfo calcDrawRate(List<? extends DrawRateDetailBuildingRateInfo> list, List<BuildingLockCount> buildingLockCounts) {
		DrawRateDetailRateInfo result = new DrawRateDetailRateInfo();
		if (CollUtil.isEmpty(list)) {
			return result;
		}
		Integer media_total_count = 0;
		int media_publish_count = 0;
		if (CollUtil.isEmpty(buildingLockCounts)) {
			for (DrawRateDetailBuildingRateInfo rateInfo : list) {
				rateInfo.setMedia_publish_count(0);
				rateInfo.setMedia_remain_count(rateInfo.getMedia_total_count());
				rateInfo.setMedia_publish_rate(BigDecimal.ZERO);
				media_total_count += rateInfo.getMedia_total_count();
			}
		} else {
			Map<Long, Integer> lockCountMap = buildingLockCounts.stream().collect(Collectors.toMap(BuildingLockCount::getBuilding_area_id, BuildingLockCount::getLock_count));
			for (DrawRateDetailBuildingRateInfo rateInfo : list) {
				Integer lockCount = lockCountMap.get(rateInfo.getBuilding_area_id());
				if (null == lockCount) {
					rateInfo.setMedia_publish_count(0);
					rateInfo.setMedia_remain_count(rateInfo.getMedia_total_count());
					rateInfo.setMedia_publish_rate(BigDecimal.ZERO);
					media_total_count += rateInfo.getMedia_total_count();
				} else {
					rateInfo.setMedia_publish_count(lockCount);
					rateInfo.setMedia_remain_count(rateInfo.getMedia_total_count() - lockCount);
					rateInfo.setMedia_publish_rate(BigDecimal.valueOf(lockCount)
							.divide(BigDecimal.valueOf(rateInfo.getMedia_total_count()), 2, RoundingMode.HALF_EVEN));
					media_total_count += rateInfo.getMedia_total_count();
					media_publish_count += lockCount;
				}
			}
		}
		Integer media_remain_count = media_total_count - media_publish_count;
		result.setMedia_total_count(media_total_count);
		result.setMedia_publish_count(media_publish_count);
		result.setMedia_remain_count(media_remain_count);
		result.setMedia_publish_rate(BigDecimal.valueOf(media_publish_count)
				.divide(BigDecimal.valueOf(media_total_count), 2, RoundingMode.HALF_EVEN));
		return result;
	}

	@Override
	public DrawRateDetailCommonVO drawRateDetailBuilding(DrawRateDetailBuildingDTO req) {
		DrawRateDetailCommonVO result = new DrawRateDetailCommonVO();
		req.initDateRange();
		List<DrawRateDetailCommonItemVO> detailCommonVOList =
				baseMapper.queryDrawRateDetailCommon(2, req.getAdcode());
		List<BuildingLockCount> buildingLockCounts =
				baseMapper.queryDrawRateDetailCommonLockCount(2,
						req.getStart_date(), req.getEnd_date(), req.getAdcode());
		DrawRateDetailRateInfo totalRate = calcDrawRate(detailCommonVOList, buildingLockCounts);
		result.setList(detailCommonVOList);
		result.setTotalRate(totalRate);
		return result;
	}

	@Override
	public DrawRateDetailGasStationVO drawRateDetailGasStation(DrawRateDetailDTO req) {
		DrawRateDetailGasStationVO result = new DrawRateDetailGasStationVO();
		req.initDateRange();
		//加油站项目列表
		List<DrawRateDetailGasStationItemVO> itemList =
				baseMapper.queryDrawRateDetailGasStation();
		//每个加油站每个媒体类型对应的媒体数量
		List<BuildingTotalCount> buildingTotalCountList =
				baseMapper.queryDrawRateDetailGasStationTypeCount();
		//每个加油站每个媒体类型对应的占用数量
		List<BuildingLockCount> buildingLockCounts =
				baseMapper.queryDrawRateDetailGasStationLockCount(req.getStart_date(), req.getEnd_date());

		Map<Integer, List<BuildingLockCount>> type2LockCountListMap = buildingLockCounts.stream()
				.collect(Collectors.groupingBy(BuildingLockCount::getMedia_type_id));

		Map<Integer, List<BuildingTotalCount>> type2TotalCountListMap = buildingTotalCountList.stream()
				.collect(Collectors.groupingBy(BuildingTotalCount::getMedia_type_id));

		//处理广告牌
		DrawRateDetailRateInfo advertisementRate = calcGasRate(itemList,
				DrawRateDetailGasStationItemVO::getAdvertisement, type2TotalCountListMap.get(5), type2LockCountListMap.get(5));
		result.setAdvertisementTotalRate(advertisementRate);
		//处理立柱
		DrawRateDetailRateInfo columnRate = calcGasRate(itemList,
				DrawRateDetailGasStationItemVO::getColumn, type2TotalCountListMap.get(6), type2LockCountListMap.get(6));
		result.setColumnTotalRate(columnRate);
		//处理加油机
		DrawRateDetailRateInfo gasMachineTotalRate = calcGasRate(itemList,
				DrawRateDetailGasStationItemVO::getGasMachine, type2TotalCountListMap.get(7), type2LockCountListMap.get(7));
		result.setGasMachineTotalRate(gasMachineTotalRate);
		result.setList(itemList);
		return result;
	}

	private DrawRateDetailRateInfo calcGasRate(
			List<DrawRateDetailGasStationItemVO> itemList,
			Function<DrawRateDetailGasStationItemVO, DrawRateDetailRateInfo> function,
			List<BuildingTotalCount> totalCountList,
			List<BuildingLockCount> lockCountList) {
		DrawRateDetailRateInfo result = new DrawRateDetailRateInfo();
		if (CollUtil.isEmpty(itemList)) {
			return result;
		}
		if (CollUtil.isEmpty(lockCountList)) {
			lockCountList = new ArrayList<>();
		}
		int media_total_count = 0;
		int media_publish_count = 0;
		//当前类型每个building对应的totalCount
		Map<Long, Integer> totalCountMap = totalCountList.stream().collect(
				Collectors.toMap(BuildingTotalCount::getBuilding_area_id, BuildingTotalCount::getMedia_total_count));
		Map<Long, Integer> lockCountMap = lockCountList.stream().collect(
				Collectors.toMap(BuildingLockCount::getBuilding_area_id, BuildingLockCount::getLock_count));

		if (CollUtil.isEmpty(lockCountList)) {
			for (DrawRateDetailGasStationItemVO rateInfo : itemList) {
				Integer totalCount = totalCountMap.get(rateInfo.getBuilding_area_id());
				DrawRateDetailRateInfo item = function.apply(rateInfo);
				item.setMedia_publish_count(0);
				item.setMedia_remain_count(totalCount);
				item.setMedia_publish_rate(BigDecimal.ZERO);
				if (null != totalCount) {
					media_total_count += totalCount;
				}

			}
		} else {
			for (DrawRateDetailGasStationItemVO rateInfo : itemList) {
				Integer lockCount = lockCountMap.get(rateInfo.getBuilding_area_id());
				Integer totalCount = totalCountMap.get(rateInfo.getBuilding_area_id());

				DrawRateDetailRateInfo item = function.apply(rateInfo);
				if (null == lockCount) {
					item.setMedia_publish_count(0);
					item.setMedia_remain_count(totalCount);
					item.setMedia_publish_rate(BigDecimal.ZERO);
					if (null != totalCount) {
						media_total_count += totalCount;
					}

				} else {
					item.setMedia_total_count(totalCount);
					item.setMedia_publish_count(lockCount);
					item.setMedia_remain_count(totalCount - lockCount);
					item.setMedia_publish_rate(BigDecimal.valueOf(lockCount)
							.divide(BigDecimal.valueOf(totalCount), 2, RoundingMode.HALF_EVEN));
					media_total_count += totalCount;
					media_publish_count += lockCount;
				}
			}
		}
		Integer media_remain_count = media_total_count - media_publish_count;
		result.setMedia_total_count(media_total_count);
		result.setMedia_publish_count(media_publish_count);
		result.setMedia_remain_count(media_remain_count);
		result.setMedia_publish_rate(BigDecimal.valueOf(media_publish_count)
				.divide(BigDecimal.valueOf(media_total_count), 2, RoundingMode.HALF_EVEN));
		return result;
	}

	@Override
	public DrawRateDetailElevatorVO drawRateDetailElevator(DrawRateDetailDTO req) {
		req.initDateRange();
		DrawRateDetailElevatorVO result = new DrawRateDetailElevatorVO();
		List<DrawRateDetailElevatorItemVO> resultList = baseMapper.queryDrawRateDetailElevatorItemTotalCountList();
		List<BuildingAreaAudienceRelation> relationList = baseMapper.queryDrawRateDetailElevatorRelationList();
		Map<Long, List<Long>> building2AudienceIdListMap = relationList.stream().collect(Collectors.groupingBy(BuildingAreaAudienceRelation::getBuilding_area_id,
				Collectors.mapping(BuildingAreaAudienceRelation::getAudience_id, Collectors.toList())));
		List<BuildingLockCount> buildingLockCounts = baseMapper.queryDrawRateDetailCommonLockCount(1, req.getStart_date(), req.getEnd_date(), null);
		for (DrawRateDetailElevatorItemVO item : resultList) {
			Long building_area_id = item.getBuilding_area_id();
			item.setAudience(building2AudienceIdListMap.get(building_area_id));
		}
		DrawRateDetailRateInfo totalRate = calcDrawRate(resultList, buildingLockCounts);
		result.setList(resultList);
		result.setTotalRate(totalRate);
		return result;
	}
}
